package edu.pucsp.predatorprey.tela;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.text.PlainDocument;

import edu.pucsp.predatorprey.FabricaSimulacao;
import edu.pucsp.predatorprey.simulador.erlang.SimuladorErlangException;
import edu.pucsp.predatorprey.simulador.java.terreno.impl.TerrenoImpl;
import edu.pucsp.predatorprey.tela.document.IntegerFilter;
import edu.pucsp.predatorprey.tela.observer.Observador;
import edu.pucsp.predatorprey.tela.util.CicloDeVida;
import edu.pucsp.predatorprey.tela.util.GridBagConstraintsBuilder;

/**
 * 
 * @author Bruno Ortiz
 * 
 */
public class PainelOpcoes extends JPanel implements Observador {

	private JTextField qtdPresas;

	private JTextField qtdPredadores;

	private final Controle controle;

	private TipoSimulador selecionado = TipoSimulador.THREADS;

	private final List<JComponent> components = new ArrayList<JComponent>();

	private JButton parar;

	public PainelOpcoes(Controle controle) {
		this.controle = controle;
		this.initComponents();
	}

	private void initComponents() {
		this.setLayout(new GridBagLayout());
		this.setBorder(BorderFactory.createTitledBorder("Opções"));
		this.qtdPresas = new JTextField("600");
		this.qtdPredadores = new JTextField("20");
		this.setIntegerFilter(this.qtdPresas);
		this.setIntegerFilter(this.qtdPredadores);

		JRadioButton threads = new JRadioButton("Threads");
		threads.setSelected(true);
		threads.addItemListener(new RadioButtonListener());
		JRadioButton actors = new JRadioButton("Actors");
		ButtonGroup buttonGroup = new ButtonGroup();
		buttonGroup.add(threads);
		buttonGroup.add(actors);

		JButton iniciar = new JButton("Iniciar");
		iniciar.addActionListener(new BotaoIniciarListener());
		this.parar = new JButton("Parar");
		this.parar.addActionListener(new BotaoPararListener());
		this.parar.setEnabled(false);

		this.add(new JLabel("Coelhos:"), GridBagConstraintsBuilder.createContraint().grid(0, 0).build());
		this.add(this.qtdPresas, GridBagConstraintsBuilder.createContraint().grid(1, 0).weightx(1.0).gridwidth(2).build());
		this.add(new JLabel("Raposas:"), GridBagConstraintsBuilder.createContraint().grid(0, 1).build());
		this.add(this.qtdPredadores, GridBagConstraintsBuilder.createContraint().grid(1, 1).weightx(1.0).gridwidth(2).build());
		this.add(new JLabel("Executar com:"), GridBagConstraintsBuilder.createContraint().grid(0, 2).build());
		this.add(threads, GridBagConstraintsBuilder.createContraint().grid(1, 2).fill(GridBagConstraints.HORIZONTAL).build());
		this.add(actors, GridBagConstraintsBuilder.createContraint().grid(1, 3).fill(GridBagConstraints.HORIZONTAL).build());
		this.add(iniciar, GridBagConstraintsBuilder.createContraint().grid(0, 4).weightx(1.0).gridwidth(3).build());
		this.add(this.parar, GridBagConstraintsBuilder.createContraint().grid(0, 5).weightx(1.0).gridwidth(3).build());

		this.qtdPresas.addFocusListener(new FocusChangedListener(this.qtdPresas));
		this.qtdPredadores.addFocusListener(new FocusChangedListener(this.qtdPredadores));

		this.components.add(this.qtdPredadores);
		this.components.add(this.qtdPresas);
		this.components.add(threads);
		this.components.add(actors);
		this.components.add(iniciar);
	}

	private void setIntegerFilter(JTextField textField) {
		PlainDocument document = (PlainDocument) textField.getDocument();
		document.setDocumentFilter(new IntegerFilter());
	}

	public void disableComponents() {
		this.setComponentsEnabled(false);
	}

	public void enableComponents() {
		this.setComponentsEnabled(true);
	}

	private void setComponentsEnabled(boolean enabled) {
		for (JComponent component : this.components) {
			component.setEnabled(enabled);
		}
	}

	private class RadioButtonListener implements ItemListener {
		@Override
		public void itemStateChanged(ItemEvent e) {
			int state = e.getStateChange();
			if (state == ItemEvent.SELECTED) {
				PainelOpcoes.this.selecionado = TipoSimulador.THREADS;
			} else if (state == ItemEvent.DESELECTED) {
				PainelOpcoes.this.selecionado = TipoSimulador.ACTORS;
			}
		}
	}

	private class BotaoIniciarListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent evt) {
			PainelOpcoes painelOpcoes = PainelOpcoes.this;
			try {
				int presas = Integer.valueOf(painelOpcoes.qtdPresas.getText());
				int predadores = Integer.valueOf(painelOpcoes.qtdPredadores.getText());
				int limite = TerrenoImpl.HEIGHT * TerrenoImpl.WIDTH;
				if (presas + predadores > limite) {
					throw new IllegalArgumentException(String.format("Valor informado de coelhos ou raposas excede o limite de %s.", limite));
				}
				painelOpcoes.controle.setSimulador(FabricaSimulacao.fabricar(painelOpcoes.selecionado, painelOpcoes.controle, presas, predadores));
				painelOpcoes.controle.iniciarSimulacao();
				painelOpcoes.disableComponents();
			} catch (SimuladorErlangException e) {
				JOptionPane.showMessageDialog(PainelOpcoes.this.getParent().getParent(), "O nó erlang não está online.");
			} catch (NumberFormatException e) {
				JOptionPane.showMessageDialog(PainelOpcoes.this.getParent().getParent(), "Valor informado de coelhos ou raposas inválido.");
			} catch (IllegalArgumentException e) {
				JOptionPane.showMessageDialog(PainelOpcoes.this.getParent().getParent(), e.getMessage());
			}
		}
	}

	private class BotaoPararListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			PainelOpcoes.this.controle.pararSimulacao();
			PainelOpcoes.this.enableComponents();
		}
	}

	@Override
	public void atualizar(CicloDeVida cicloDeVida) {
		if (CicloDeVida.PAROU.equals(cicloDeVida)) {
			this.enableComponents();
			this.parar.setEnabled(false);
		} else if (CicloDeVida.COMECOU.equals(cicloDeVida)) {
			this.parar.setEnabled(true);
		}
	}

	private class FocusChangedListener extends FocusAdapter {

		private final JTextField component;

		public FocusChangedListener(JTextField component) {
			this.component = component;
		}

		@Override
		public void focusLost(FocusEvent e) {
			if (this.component.getText().equals("")) {
				this.component.setText("0");
			}
		}

	}
}
